package com.touchapk.javafx;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;

import org.fxmisc.flowless.VirtualizedScrollPane;
import org.fxmisc.richtext.CodeArea;
import org.fxmisc.richtext.LineNumberFactory;
import org.fxmisc.richtext.model.StyleSpans;
import org.fxmisc.richtext.model.StyleSpansBuilder;

public class LuaKeywords {

	private boolean isLua;
	private String filePath;
	public LuaKeywords(String filePath,boolean isLua){
		this.filePath=filePath;
		this.isLua=isLua;
	}
	
	private String code;
	
	private CodeArea codeArea = new CodeArea();
	
	public  CodeArea getCodeArea(){
		return this.codeArea;
	}
	
    private static final String[] KEYWORDS = new String[] {
            "and", "break", "do", "else", "elseif",
            "end", "false", "for", "function", "if",
            "in", "local", "nil", "not", "or",
            "repeat", "return", "then", "true", "until",
            "while"
    };
    
    private static final String KEYWORD_PATTERN = "\\b(" + String.join("|", KEYWORDS) + ")\\b";
    private static final String PAREN_PATTERN = "\\(|\\)";
    private static final String BRACE_PATTERN = "\\{|\\}";
    private static final String BRACKET_PATTERN = "\\[|\\]";
    private static final String SEMICOLON_PATTERN = "\\;";
    private static final String STRING_PATTERN = "\"([^\"\\\\]|\\\\.)*\"";
    private static final String COMMENT_PATTERN = "--[^\n]*" ;
    private static final String COMMENT_MULTI_START_PATTERN ="--\\[\\[(.|\\R)*";
    private static final String COMMENT_MULTI_ALL_PATTERN ="--\\[\\[(.|\\R)*?--\\]\\]";

    private static final Pattern PATTERN = Pattern.compile(
            "(?<KEYWORD>" + KEYWORD_PATTERN + ")"
            + "|(?<PAREN>" + PAREN_PATTERN + ")"
            + "|(?<BRACE>" + BRACE_PATTERN + ")"
            + "|(?<BRACKET>" + BRACKET_PATTERN + ")"
            + "|(?<SEMICOLON>" + SEMICOLON_PATTERN + ")"
            + "|(?<STRING>" + STRING_PATTERN + ")"
            + "|(?<COMMENTALL>" + COMMENT_MULTI_ALL_PATTERN + ")"
            + "|(?<COMMENTSTART>" + COMMENT_MULTI_START_PATTERN + ")"
            + "|(?<COMMENT>" + COMMENT_PATTERN + ")"
    );

   
    
    
    public String getCodeFromFile() {
    	try {
			FileInputStream in=new FileInputStream(new File(filePath));
			int o=-1;
			ByteArrayOutputStream bo=new ByteArrayOutputStream();
			while((o=in.read())!=-1){
				bo.write(o);
			}
			return bo.toString("UTF-8");
		} catch (FileNotFoundException e) {
		
			System.out.println("文件不存在");
		} catch (IOException e) {
			
			System.out.println("读取文件出错");
		}
    	return "";
    }
    
    public void saveCodeToFile(){
    	try {
			FileOutputStream out=new FileOutputStream(new File(filePath));
			
			BufferedWriter rd = new BufferedWriter(new OutputStreamWriter(out,"utf-8"));
			 rd.write(codeArea.getText());
			 out.flush();
			 rd.close();
			 out.close();
			
		} catch (FileNotFoundException e) {
			System.out.println("文件不存在");
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }

    

    public StackPane getStackPane() {
    	
        codeArea.setParagraphGraphicFactory(LineNumberFactory.get(codeArea));

        if(isLua){
	        codeArea.richChanges()
	                .filter(ch -> !ch.getInserted().equals(ch.getRemoved())) // XXX
	                .subscribe(change -> {
	                    codeArea.setStyleSpans(0, computeHighlighting(codeArea.getText()));
	                });
	      }
        
        code=getCodeFromFile();
        codeArea.replaceText(0, 0, code);
        
        StackPane stackPane =  new StackPane(new VirtualizedScrollPane<>(codeArea));
        if(isLua){
        	stackPane.getStylesheets().add(LuaKeywords.class.getResource("lua-keywords.css").toExternalForm());
        }
        return stackPane;
    }
    
    

    
    public void call(KeyEvent event){
    	if(event.isControlDown()&&"S".equals(event.getCode().toString())){
			//保存
			saveCodeToFile();
		}else if(event.isControlDown()&&"Z".equals(event.getCode().toString())){
			if("".equals(codeArea.getText())){
				 codeArea.replaceText(0, 0, code);
			}
		}
    }
    
    
    private static StyleSpans<Collection<String>> computeHighlighting(String text) {
    	
    	
        Matcher matcher = PATTERN.matcher(text);
        int lastKwEnd = 0;
        StyleSpansBuilder<Collection<String>> spansBuilder = new StyleSpansBuilder<>();
        while(matcher.find()) {
            String styleClass =
                    matcher.group("KEYWORD") != null ? "keyword" :
                    matcher.group("PAREN") != null ? "paren" :
                    matcher.group("BRACE") != null ? "brace" :
                    matcher.group("BRACKET") != null ? "bracket" :
                    matcher.group("SEMICOLON") != null ? "semicolon" :
                    matcher.group("STRING") != null ? "string" :
                    matcher.group("COMMENTALL") != null ? "comment" :
                    matcher.group("COMMENTSTART") != null ? "comment" :
                    matcher.group("COMMENT") != null ? "comment" :
                    null; /* never happens */ assert styleClass != null;
            spansBuilder.add(Collections.emptyList(), matcher.start() - lastKwEnd);
            spansBuilder.add(Collections.singleton(styleClass), matcher.end() - matcher.start());
            lastKwEnd = matcher.end();
        }
        spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd);
        return spansBuilder.create();
    }
}
